﻿
namespace ShoppingCart.DataAccess
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using Microsoft.Practices.EnterpriseLibrary.Data;
    using Business.Entity;
    using Business.Entity.Collections;

	/// <summary>
	/// Represents the DataAccess of BancoData.
	/// </summary>
	public class BancoData : Singleton<BancoData>
	{
		#region Attributes

		private readonly Database BaseDatos = DatabaseFactory.CreateDatabase();

		#endregion

		#region Methods

		/// <summary>
		/// Selects all records from the Banco table by a foreign key.
		/// </summary>
		public IList<Banco> Listar()
		{
			var entidades = new List<Banco>();
			var comando = BaseDatos.GetStoredProcCommand("SelectAllBanco");

			using (var lector = BaseDatos.ExecuteReader(comando))
			{
				while (lector.Read())
				{
					entidades.Add(new Banco
					{
						IdBanco = lector.GetInt32(lector.GetOrdinal("IdBanco")),
						Nombre = lector.GetString(lector.GetOrdinal("Nombre")),
						Descripcion = lector.IsDBNull(lector.GetOrdinal("Descripcion"))? default(string) : lector.GetString(lector.GetOrdinal("Descripcion"))
					});
				}
			}
			comando.Dispose();
			return entidades;
		}

		/// <summary>
		/// Selects all records from the Banco table by a foreign key.
		/// </summary>
		public Banco Obtener(int idBanco)
		{
			var banco = default(Banco);
			var comando = BaseDatos.GetStoredProcCommand("SelectBanco");

			BaseDatos.AddInParameter(comando, "IdBanco", DbType.Int32, idBanco);

			using (var lector = BaseDatos.ExecuteReader(comando))
			{
				while (lector.Read())
				{
					banco = new Banco
					{
						IdBanco = idBanco,
						Nombre = lector.GetString(lector.GetOrdinal("Nombre")),
						Descripcion = lector.IsDBNull(lector.GetOrdinal("Descripcion"))? default(string) : lector.GetString(lector.GetOrdinal("Descripcion")),
                        Cuentas = CuentaData.Instancia.ListarPorIdBanco(idBanco)
					};
				}
			}
			comando.Dispose();
			return banco;
		}

		/// <summary>
		/// Saves a record to the Banco table.
		/// </summary>
        public int Agregar(Banco banco)
        {
            using (var connection = BaseDatos.CreateConnection())
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        var comandoBanco = BaseDatos.GetStoredProcCommand("InsertBanco");
                        BaseDatos.AddOutParameter(comandoBanco, "IdBanco", DbType.Int32, 4);
                        BaseDatos.AddInParameter(comandoBanco, "Nombre", DbType.String, banco.Nombre);
                        BaseDatos.AddInParameter(comandoBanco, "Descripcion", DbType.String, banco.Descripcion);

                        var resultado = BaseDatos.ExecuteNonQuery(comandoBanco, transaction);
                        if (resultado == 0) throw new Exception("Error al Agregar Banco.");
                        var valorDevuelto = (int)BaseDatos.GetParameterValue(comandoBanco, "IdBanco");

                        var comandoCuenta = BaseDatos.GetStoredProcCommand("InsertCuenta");
                        BaseDatos.AddOutParameter(comandoCuenta, "IdCuenta", DbType.Int32, 4);
                        BaseDatos.AddInParameter(comandoCuenta, "IdBanco", DbType.Int32);
                        BaseDatos.AddInParameter(comandoCuenta, "Numero", DbType.String);
                        BaseDatos.AddInParameter(comandoCuenta, "Tipo", DbType.Byte);

                        foreach (var cuenta in banco.Cuentas)
                        {
                            BaseDatos.SetParameterValue(comandoCuenta, "IdBanco", valorDevuelto);
                            BaseDatos.SetParameterValue(comandoCuenta, "Numero", cuenta.Numero);
                            BaseDatos.SetParameterValue(comandoCuenta, "Tipo", cuenta.Tipo);

                            resultado = BaseDatos.ExecuteNonQuery(comandoCuenta, transaction);
                            if (resultado == 0) throw new Exception("Error al Agregar Cuenta.");
                        }

                        transaction.Commit();
                        comandoCuenta.Dispose();
                        comandoBanco.Dispose();

                        return valorDevuelto;
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }

		/// <summary>
		/// Updates a record in the Banco table.
		/// </summary>
		public bool Modificar(Banco banco)
		{
            using (var connection = BaseDatos.CreateConnection())
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    try
                    {
                        var comandoBanco = BaseDatos.GetStoredProcCommand("UpdateBanco");
                        BaseDatos.AddInParameter(comandoBanco, "IdBanco", DbType.Int32, 4);
                        BaseDatos.AddInParameter(comandoBanco, "Nombre", DbType.String, banco.Nombre);
                        BaseDatos.AddInParameter(comandoBanco, "Descripcion", DbType.String, banco.Descripcion);

                        var resultado = BaseDatos.ExecuteNonQuery(comandoBanco, transaction);
                        if (resultado == 0) throw new Exception("Error al Agregar Banco.");

                        var cuentas = new CuentaCollection();
                        var comandoCuenta = BaseDatos.GetStoredProcCommand("SelectCuentaByIdBanco");
                        BaseDatos.AddInParameter(comandoCuenta, "IdBanco", DbType.Int32, banco.IdBanco);
                        using (var lector = BaseDatos.ExecuteReader(comandoCuenta))
                        {
                            while (lector.Read())
                            {
                                cuentas.Add(new Cuenta { IdCuenta = lector.GetInt32(lector.GetOrdinal("IdCuenta")) });
                            }
                        }
                        comandoCuenta = BaseDatos.GetStoredProcCommand("DeleteCuenta");
                        BaseDatos.AddInParameter(comandoCuenta, "IdCuenta", DbType.Int32);
                        foreach (var cuenta in cuentas)
                        {
                            if (banco.Cuentas.Any(p => p.Numero == cuenta.Numero)) continue;
                            BaseDatos.SetParameterValue(comandoCuenta, "IdCuenta", cuenta.IdCuenta);
                            BaseDatos.ExecuteNonQuery(comandoCuenta, transaction);
                        }

                        comandoCuenta = BaseDatos.GetStoredProcCommand("InsertCuenta");
                        BaseDatos.AddOutParameter(comandoCuenta, "IdCuenta", DbType.Int32, 4);
                        BaseDatos.AddInParameter(comandoCuenta, "IdBanco", DbType.Int32);
                        BaseDatos.AddInParameter(comandoCuenta, "Numero", DbType.String);
                        BaseDatos.AddInParameter(comandoCuenta, "Tipo", DbType.Byte);

                        foreach (var cuenta in banco.Cuentas)
                        {
                            BaseDatos.SetParameterValue(comandoCuenta, "IdBanco", banco.IdBanco);
                            BaseDatos.SetParameterValue(comandoCuenta, "Numero", cuenta.Numero);
                            BaseDatos.SetParameterValue(comandoCuenta, "Tipo", cuenta.Tipo);

                            resultado = BaseDatos.ExecuteNonQuery(comandoCuenta, transaction);
                            if (resultado == 0) throw new Exception("Error al Agregar Cuenta.");
                        }

                        transaction.Commit();
                        comandoCuenta.Dispose();
                        comandoBanco.Dispose();

                        return true;
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
		}

		/// <summary>
		/// Deletes a record from the Banco table by its primary key.
		/// </summary>
		public bool Eliminar(int idBanco)
		{
			var comando = BaseDatos.GetStoredProcCommand("DeleteBanco");
			BaseDatos.AddInParameter(comando, "IdBanco", DbType.Int32, idBanco);

			var resultado = BaseDatos.ExecuteNonQuery(comando);
			if (resultado == 0) throw new Exception("Error al Eliminar Banco.");
			comando.Dispose();
			return true;
		}

		#endregion
	}
}
